/*
 * C6.3.3.c
 *
 *  Created on: 2012/12/18
 *      Author: ming
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rule_info.h"
#include "core.h"

static const PSZ RuleID = "C6.3.3";

static const PSZ SHARP_DEFINE = "#define";
static const PSZ SHARP_UNDEF = "#undef";

static const PSZ MESSAGE_ENG = "Using '%s' in block statement";
static const PSZ MESSAGE_JPN = "ブロック内で'%s'が使用されている";
static const PSZ MESSAGE_CHS = "在函数定义中使用了'%s'";

static const U2 RANK = MSG_RANK_ERR;

static PRULEOUT pRuleHead;
static PRULEOUT pRuleTail;

static AST TU_FILE;

static S4 BEG_END_LINE[2];

static BOOL isStmtInTuFile(AST index) {
	AST file = CCodeScope.getFileIndex(CStatement.getCodeScope(index));
	if (file == TU_FILE) {
		return TRUE;
	}
	return FALSE;
}

static BOOL isDirectiveInTuFile(AST index) {
	AST file = CCodeScope.getFileIndex(CDirectiveInfo.getCodeScp(index));
	if (file == TU_FILE) {
		return TRUE;
	}
	return FALSE;
}

static VOID loadBegEndLine(AST stmt) {
	AST scp = CStatement.getCodeScope(stmt);
	BEG_END_LINE[0] = CCodeScope.getBeginLine(scp);
	BEG_END_LINE[1] = CCodeScope.getEndLine(scp);
}

static BOOL isInBlock(AST index) {
	AST stmt;
	AST stmtMax = CStatement.getMax();
	AST line = CCodeScope.getBeginLine(CDirectiveInfo.getCodeScp(index));
	for (stmt = 1; stmt <= stmtMax; stmt++) {
		if (!CStatement.isBlock(stmt)) {
			continue;
		}
		if (isStmtInTuFile(stmt)) {
			loadBegEndLine(stmt);
			if (isDirectiveInTuFile(index)) {
				if (BEG_END_LINE[0] <= line && line <= BEG_END_LINE[1]) {
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

/******************************************************************
 * main logic
 *******************************************************************/
static S4 RuleMain(AST index, AST tuIdx) {
	INT result = RULE_RESULT_OK;
	PRULEOUT newNode = NULL;
	PRULEOUT tmpNode = NULL;
	PRULEOUT tmpNode1 = NULL;

	AST codeScp = 0;
	PSZ opName = NULL;

	TU_FILE = CTranslationUnit.getFileIndex(tuIdx);

	if (CDirectiveInfo.isDefine(index)) {
		opName = SHARP_DEFINE;
	} else if (CDirectiveInfo.isUndef(index)) {
		opName = SHARP_UNDEF;
	} else {
		return EXIT_SUCCESS;
	}

	if (isInBlock(index)) {
		result = RULE_RESULT_NG;
	}

	if (result == RULE_RESULT_OK) {
		return EXIT_SUCCESS;
	}

	/*re-checked?*/
	tmpNode = pRuleHead;
	while (tmpNode != NULL ) {
		if (tmpNode->indexInfo == index) {
			if (result > RULE_RESULT_OK) {
				result = RULE_RESULT_OK;
			} else {
				if (tmpNode == pRuleHead) {
					pRuleHead = pRuleHead->next;
					free(tmpNode);
				} else if (tmpNode == pRuleTail) {
					tmpNode1->next = NULL;
					pRuleTail = tmpNode1;
					free(tmpNode);
				} else {
					tmpNode1->next = tmpNode->next;
					free(tmpNode);
				}
			}
			break;
		}
		tmpNode1 = tmpNode;
		tmpNode = tmpNode->next;
	}

	/*make result struct*/
	if (result > RULE_RESULT_OK) {
		newNode = (PRULEOUT) malloc(sizeof(RULEOUT));
		if (pRuleHead == NULL ) {
			pRuleHead = newNode;
		}

		codeScp = CDirectiveInfo.getCodeScp(index);
		newNode->indexInfo = index;
		newNode->fileIndex = CCodeScope.getFileIndex(codeScp);
		newNode->beginLine = CCodeScope.getBeginLine(codeScp);
		newNode->beginCol = CCodeScope.getBeginLineOffset(codeScp);
		newNode->endLine = CCodeScope.getEndLine(codeScp);
		newNode->endCol = CCodeScope.getEndLineOffset(codeScp);
		newNode->ruleID = RuleID;
		newNode->errRank = RANK;

		sprintf(newNode->msgBuf_eng, MESSAGE_ENG, opName);
		sprintf(newNode->msgBuf_chs, MESSAGE_CHS, opName);
		sprintf(newNode->msgBuf_jpn, MESSAGE_JPN, opName);

		newNode->rfileIndex = 0;
		newNode->rlocLine = 0;
		newNode->next = NULL;

		if (pRuleTail != NULL ) {
			pRuleTail->next = newNode;
		}

		pRuleTail = newNode;
	}

	return EXIT_SUCCESS;
}

VOID C6_3_3_register(VOID) {
	PRULEMAN * pCurRule = &stRuleManager;
	PRULEMAN newRuleMan = (PRULEMAN) malloc(sizeof(RULEMAN));
	memset(newRuleMan, 0, sizeof(RULEMAN));
	newRuleMan->ruleID = RuleID;
	newRuleMan->ruleSwitch = OFF;
	newRuleMan->headOut = &pRuleHead;
	newRuleMan->tailOut = &pRuleTail;
	newRuleMan->ruleMain_cpp = RuleMain;
	if (stRuleManager == NULL ) {
		stRuleManager = newRuleMan;
	} else {
		while ((*pCurRule)->nextRule != NULL ) {
			pCurRule = &((*pCurRule)->nextRule);
		}
		(*pCurRule)->nextRule = newRuleMan;
	}
}
